package network

import (
	"context"
	"fmt"
	blc "github.com/corgi-kx/blockchain_golang/blc"
	log "github.com/corgi-kx/logcustom"
	pubsub "github.com/libp2p/go-libp2p-pubsub"
	"math/big"
	"os"
	"sync"
)

func pubsubHandler(ctx context.Context, sub *pubsub.Subscription) {
	for {
		msg, err := sub.Next(ctx)
		if err != nil {
			_, _ = fmt.Fprintln(os.Stderr, err)
			continue
		}
		//取信息的前十二位得到命令
		cmd, content := SplitMessage(msg.Data)

		log.Tracef("本节点已接收到命令：%s", cmd)
		switch command(cmd) {
		case cVersion:
			go handleVersion(content)
		case cABHeader:
			go handleBlockHeader(content)
		case cMyError:
			go handleMyError(content)
		}

	}
}

//接收到区块头的处理函数
func handleBlockHeader(content []byte) {
	//首先解析地址信息
	abh := DeserializeAddrMapBlockHeader(content)
	addr := abh.Addr
	port := abh.Port
	//先不做存储
	blockHeader := blc.DeserializeBlockHeader(abh.BlockHeaderByte)
	//比当前挖矿的高度高才允许挖矿，或者当前没有在挖矿，允许挖矿
	if blockHeader.Height > blc.NowPowHeight || blc.NowPowHeight == 0 {
		target := big.NewInt(1)
		//返回一个大数(1 << 256-TargetBits)
		//target.Lsh(target, 256- blc.TargetBits)
		//根据区块头难度值构造大数
		target.SetBytes(blockHeader.Difficulty)

		pow := blc.ProofOfWork{
			BlockHeader: blockHeader,
			Target:      target,
		}
		blc.AsyncMine(&pow, send, addr, port)
		return
	} else {
		return
	}

}

//打印接收到的错误信息
func handleMyError(content []byte) {
	e := myerror{}
	e.deserialize(content)
	log.Warn(e.Error)
	peer := buildPeerInfoByAddr(e.Addrfrom)
	delete(peerPool, fmt.Sprint(peer.ID))
}

//接收到其他节点的区块高度信息,与本地区块高度进行对比
func handleVersion(content []byte) {
	//接收到高度信息，进行处理
	var lock sync.Mutex
	lock.Lock()
	defer lock.Unlock()
	v := version{}
	v.deserialize(content)

	if blc.NewestBlockHeight > v.Height {
		log.Info("目标高度比本次挖矿的高度小，不予处理")
	} else if blc.NewestBlockHeight < v.Height {
		log.Debugf("节点%v发送过来的高度比我们的大,替换本节点的高度信息，停止挖矿", v)
		blc.NewestBlockHeight = v.Height
	} else {
		log.Debug("接收到版本信息，双方高度一致，无需处理！")
		//log.Debugf("节点%v发送过来的高度信息与当前一致，停止当前挖矿",v)
		//blc.NewestBlockHeight = v.Height
	}
}
